iT邦幫忙

2024 iThome 鐵人賽

DAY 0
0
自我挑戰組

ASP.NET Core生成網站記錄系列 第 6

DAY6-Dapper 與 EF Core

  • 分享至 

  • xImage
  •  

Dapper 是一個工具箱: 它提供了一套工具,讓你能夠高效地執行 SQL 語句,但它不負責管理你的資料模型或生成資料庫結構。

EF Core 是一個框架: 它提供了一個完整的 ORM 框架,可以自動生成資料庫結構,並提供豐富的功能來管理你的資料模型。

各自擅長領域: Dapper擅長於執行複雜的 SQL 查詢,而 EF Core 擅長於管理物件關係映射和自動遷移。
彈性組合: 您可以根據不同的需求,在同一個專案中選擇使用 Dapper 或 EF Core。
互補性: 在某些場景下,兩者可以互相補強。例如,您可以使用 EF Core 來管理大部分的資料操作,而對於性能要求極高的部分,則可以使用 Dapper 來手寫 SQL。
常見的結合使用方式
混合查詢:

使用 EF Core 建立 DbContext,並利用 FromSqlRaw 或 FromSqlInterpolated 方法執行 Dapper 式的查詢。
這樣可以結合 EF Core 的物件映射功能和 Dapper 的 SQL 靈活性。
存儲過程:

使用 EF Core 來定義存儲過程的參數和返回值,然後使用 Dapper 來執行這些存儲過程。
這可以將複雜的業務邏輯封裝在存儲過程中,提高系統的性能和安全性。
批量插入/更新:

Dapper 在批量插入和更新方面通常比 EF Core 具有更好的性能。
可以使用 Dapper 來執行批量操作,而其他資料操作則使用 EF Core。
特定查詢優化:

對於一些性能要求極高的查詢,可以使用 Dapper 手寫 SQL 來優化。
其他查詢則繼續使用 EF Core 的 LINQ to Entities。
範例:在 EF Core DbContext 中使用 Dapper
C#
using Dapper;

public class MyDbContext : DbContext
{
public DbSet Students { get; set; }

public List<Student> GetStudentsByCustomQuery(string name)
{
    using (var connection = Database.GetDbConnection())
    {
        return connection.Query<Student>("SELECT * FROM Students WHERE Name LIKE @name", new { name = $"%{name}%" }).ToList();
    }
}

}

  1. using Dapper;

這行指令引入了 Dapper 這個 .NET 函式庫。Dapper 是一個微型的物件關係映射器(ORM),能讓我們更方便地將資料庫查詢結果映射到 .NET 物件。
2. public class MyDbContext : DbContext

MyDbContext 這個類別繼承自 DbContext,這表示它是一個 Entity Framework Core 的資料庫上下文類別。這個類別是我們與資料庫互動的橋樑。
3. public DbSet Students { get; set; }

這行定義了一個 DbSet 集合,名稱為 Students,其元素類型為 Student。DbSet 代表資料庫中的一張表,也就是 Students 這張表。
4. public List GetStudentsByCustomQuery(string name)

這個方法會返回一個 Student 物件的列表,並接受一個 string 型態的 name 作為參數。這個方法的目的是根據傳入的名稱來查詢學生資料。
5. using (var connection = Database.GetDbConnection())

這是一個 using 區塊,用來確保資料庫連線在使用完畢後會被正確地關閉。Database.GetDbConnection() 方法會取得一個資料庫連線物件。
6. return connection.Query("SELECT * FROM Students WHERE Name LIKE @name", new { name = $"%{name}%" }).ToList();

這行是核心查詢部分:
connection.Query():這行呼叫 Dapper 的 Query 方法,將查詢結果映射到 Student 物件。
"SELECT * FROM Students WHERE Name LIKE @name":這是一個 SQL 查詢,用來從 Students 表中查詢所有 Name 欄位包含 name 的資料。@name 是參數,用來防止 SQL 注入攻擊。
new { name = $"%{name}%" }: 這是一個匿名物件,將 name 參數的值加上 % 通配符,用於模糊查詢。
.ToList():將查詢結果轉換為一個 List,方便我們後續處理。

dapper的這幾種方法 Execute

Query

QueryFirst

QueryFirstOrDefault

QuerySingle

QuerySingleOrDefault

QueryMultiple

Insert/Update/Delete

Transaction   

Dapper 常用方法與學生表範例
Dapper 是一個微型 ORM,提供了一組強大的工具來與資料庫進行互動。以下將針對您提到的 Dapper 方法,結合學生表(Students)來詳細說明:

基本查詢方法
Execute:
用於執行不返回結果集的 SQL 指令,例如:插入、更新、刪除。
範例:刪除學號為 1 的學生
C#
connection.Execute("DELETE FROM Students WHERE StudentId = @Id", new { Id = 1 });
請謹慎使用程式碼。

Query:
用於執行返回多個結果集的 SQL 指令,並將結果映射到指定的物件。
範例:查詢所有學生
C#
var students = connection.Query<Student>("SELECT * FROM Students");
請謹慎使用程式碼。

QueryFirst:
只返回第一個符合條件的結果。若無結果,則拋出異常。
範例:查詢第一個名字為 "張三" 的學生
C#
var student = connection.QueryFirst<Student>("SELECT * FROM Students WHERE Name = @Name", new { Name = "張三" });
請謹慎使用程式碼。

QueryFirstOrDefault:
與 QueryFirst 相似,但若無結果,則返回預設值(通常是該類型的 null)。
範例:查詢第一個名字為 "李四" 的學生,若無則返回 null
C#
var student = connection.QueryFirstOrDefault<Student>("SELECT * FROM Students WHERE Name = @Name", new { Name = "李四" });
請謹慎使用程式碼。

QuerySingle:
只返回一個結果。若有多個結果或沒有結果,則拋出異常。
範例:查詢學號為 1 的學生(假設學號為唯一)
C#
var student = connection.QuerySingle<Student>("SELECT * FROM Students WHERE StudentId = @Id", new { Id = 1 });
請謹慎使用程式碼。

QuerySingleOrDefault:
與 QuerySingle 相似,但若無結果,則返回預設值(通常是該類型的 null)。
範例:查詢學號為 2 的學生(假設學號為唯一),若無則返回 null
C#
var student = connection.QuerySingleOrDefault<Student>("SELECT * FROM Students WHERE StudentId = @Id", new { Id = 2 });
請謹慎使用程式碼。

QueryMultiple:
用於執行返回多個結果集的 SQL 指令,並將每個結果集映射到不同的物件。
範例:查詢學生和其對應的課程(假設有兩張表 Students 和 Courses)
C#
using (var multi = connection.QueryMultiple("SELECT * FROM Students; SELECT * FROM Courses"))
{
    var students = multi.Read<Student>();
    var courses = multi.Read<Course>();
}
請謹慎使用程式碼。

CRUD 操作
Insert: 使用 Execute 方法,並提供 INSERT SQL 指令。
Update: 使用 Execute 方法,並提供 UPDATE SQL 指令。
Delete: 使用 Execute 方法,並提供 DELETE SQL 指令。
範例:新增一個學生

C#
connection.Execute("INSERT INTO Students (Name, Age) VALUES (@Name, @Age)", new { Name = "王五", Age = 20 });
請謹慎使用程式碼。

Transaction
Dapper 支援事務,確保一組 SQL 指令的原子性。
範例:新增一個學生並同時插入其選課資訊
C#
using (var transaction = connection.BeginTransaction())
{
    try
    {
        connection.Execute("INSERT INTO Students (Name, Age) VALUES (@Name, @Age)", new { Name = "李四", Age = 21 }, transaction);
        connection.Execute("INSERT INTO Enrollments (StudentId, CourseId) VALUES (@StudentId, @CourseId)", new { StudentId = lastInsertedId, CourseId = 1 }, transaction);
        transaction.Commit();
    }
    catch
    {
        transaction.Rollback();
        throw;
    }
}
請謹慎使用程式碼。

小結
Dapper 提供了豐富的方法來與資料庫進行互動。選擇哪個方法,取決於您要執行的 SQL 操作的類型和期望的結果。

Execute: 用於不返回結果集的 SQL 操作。
Query: 用於返回多個結果集的 SQL 操作。
QueryFirst/FirstOrDefault/Single/SingleOrDefault: 用於返回單一結果或預設值。
QueryMultiple: 用於返回多個結果集。
Dapper 與傳統 SQL 搭配 DataSet、DataTable 的性能與靈活性比較
性能比較
Dapper:
直接映射: Dapper 能直接將查詢結果映射到 .NET 物件,減少了中間層的轉換,提高了性能。
參數化查詢: 避免了 SQL 注入,提升了安全性。
批量操作優化: Dapper 在批量插入、更新、刪除等操作上通常有優化的實現,性能較佳。
傳統 SQL 搭配 DataSet、DataTable:
中間層轉換: 需要將數據從資料庫讀取到 DataSet 或 DataTable 中,再逐行轉換成 .NET 物件,增加了性能開銷。
SQL 注入風險: 若未妥善處理,容易受到 SQL 注入攻擊。
程式碼複雜度較高: 需要手動處理資料的讀取、轉換和填充,程式碼較為冗長。
總結:
Dapper 在性能上具有明顯優勢,特別是在大批量數據操作和複雜查詢方面。它能更有效地利用資料庫資源,減少不必要的數據轉換。

靈活性比較
Dapper:
自由度高: 可以直接執行任意的 SQL 指令,包括複雜的 JOIN、子查詢等。
強型別映射: 能將查詢結果直接映射到 .NET 物件,方便操作。
傳統 SQL 搭配 DataSet、DataTable:
靈活性較低: 受到 DataSet 和 DataTable 的限制,在處理複雜的資料結構時可能不夠靈活。
類型轉換繁瑣: 需要手動將數據從 DataTable 中讀取並轉換成 .NET 類型。
總結:
Dapper 提供了更高的靈活性,可以滿足各種複雜的資料庫操作需求。而傳統方式則相對受限。

示例:查詢學生資訊並計算平均成績
Dapper:

C#
var students = connection.Query<Student>("SELECT StudentId, Name, AVG(Score) AS AverageScore FROM StudentScores GROUP BY StudentId, Name");
請謹慎使用程式碼。

傳統方式 (假設使用 ADO.NET):

C#
using (var command = new SqlCommand("SELECT StudentId, Name, AVG(Score) AS AverageScore FROM StudentScores GROUP BY StudentId, Name", connection))
{
    using (var reader = command.ExecuteReader())
    {
        var students = new List<Student>();
        while (reader.Read())
        {
            var student = new Student
            {
                StudentId = reader.GetInt32(0),
                Name = reader.GetString(1),
                AverageScore = reader.GetDouble(2)
            };
            students.Add(student);
        }
        return students;
    }
}
請謹慎使用程式碼。

比較:

Dapper 的寫法更加簡潔,直接將查詢結果映射到 Student 物件。
傳統方式需要手動處理 SqlDataReader,將數據逐一讀取並填充到 Student 物件中,程式碼較為冗長。
總結
Dapper 在性能、靈活性、開發效率等方面都優於傳統的 SQL 搭配 DataSet、DataTable 的方式。它能讓開發者更專注於業務邏輯,而不用過多地關心底層的資料庫操作細節。

何時選擇 Dapper:

性能要求高: 特別是大批量數據操作和複雜查詢。
需要靈活的 SQL 操作: Dapper 可以執行任意的 SQL 指令。
希望簡化程式碼: Dapper 提供了更簡潔的語法。
何時考慮傳統方式:

已有大量基於 DataSet、DataTable 的程式碼: 短期內可能不適合全面遷移。
對 SQL 有深入了解: 希望對資料庫操作有更精細的控制。

上一篇
DAY5-ADO.NET和ORM(ADO.NET 類別)
下一篇
DAY8- ASP.NET Core 的 Program.cs 檔案
系列文
ASP.NET Core生成網站記錄31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言